/**
 * Sub-Agents Manager
 * 
 * Manages Claude Sub-Agents - specialized agents that can be automatically invoked
 * by the main agent based on task descriptions.
 * 
 * Based on Claude Agent SDK documentation:
 * https://docs.claude.com/en/api/agent-sdk/subagents
 */

import { logger } from '@/utils/logger';
import type { SkillsManager } from '@/skills/skill-manager';

/**
 * Sub-Agent configuration
 */
export interface SubAgentConfig {
  id: string;
  name: string;
  description: string; // Used by Claude to decide when to invoke this sub-agent
  prompt: string; // System prompt defining the sub-agent's role and behavior
  tools?: string[]; // Optional: specific tools this sub-agent can use (inherits all if omitted)
  model?: 'sonnet' | 'opus' | 'haiku' | 'inherit'; // Model override
  skillIds?: string[]; // Optional: associate with Skills to inherit tools and prompts
  category?: SubAgentCategory;
  tags?: string[];
  isBuiltin?: boolean;
  metadata?: Record<string, any>;
}

/**
 * Sub-Agent categories
 */
export type SubAgentCategory =
  | 'development'
  | 'testing'
  | 'security'
  | 'documentation'
  | 'analysis'
  | 'devops'
  | 'custom';

/**
 * SDK-compatible agent configuration
 * This is the format expected by Claude Agent SDK's `agents` parameter
 */
export interface SdkAgentConfig {
  description: string;
  prompt: string;
  tools?: string[];
  model?: 'sonnet' | 'opus' | 'haiku' | 'inherit';
}

/**
 * Sub-Agents Manager
 * 
 * Manages registration, discovery, and configuration of sub-agents
 * Integrates with SkillsManager to allow sub-agents to inherit Skills' tools and prompts
 */
export class SubAgentManager {
  private subagents: Map<string, SubAgentConfig> = new Map();
  private skillsManager?: SkillsManager;

  constructor(skillsManager?: SkillsManager) {
    this.skillsManager = skillsManager;
  }

  /**
   * Register a sub-agent
   */
  registerSubAgent(config: SubAgentConfig): void {
    logger.info(`Registering sub-agent: ${config.name} (${config.id})`);
    
    if (this.subagents.has(config.id)) {
      logger.warn(`Sub-agent ${config.id} already registered, overwriting`);
    }
    
    this.subagents.set(config.id, config);
  }

  /**
   * Register multiple sub-agents
   */
  registerSubAgents(configs: SubAgentConfig[]): void {
    configs.forEach(config => this.registerSubAgent(config));
  }

  /**
   * Get a sub-agent by ID
   */
  getSubAgent(id: string): SubAgentConfig | undefined {
    return this.subagents.get(id);
  }

  /**
   * Get all registered sub-agents
   */
  getAllSubAgents(): SubAgentConfig[] {
    return Array.from(this.subagents.values());
  }

  /**
   * Get sub-agents by category
   */
  getSubAgentsByCategory(category: SubAgentCategory): SubAgentConfig[] {
    return this.getAllSubAgents().filter(agent => agent.category === category);
  }

  /**
   * Search sub-agents by name or description
   */
  searchSubAgents(query: string): SubAgentConfig[] {
    const lowerQuery = query.toLowerCase();
    return this.getAllSubAgents().filter(agent =>
      agent.name.toLowerCase().includes(lowerQuery) ||
      agent.description.toLowerCase().includes(lowerQuery)
    );
  }

  /**
   * Remove a sub-agent
   */
  removeSubAgent(id: string): boolean {
    const agent = this.getSubAgent(id);
    if (!agent) {
      logger.error(`Cannot remove sub-agent ${id}: not found`);
      return false;
    }

    if (agent.isBuiltin) {
      logger.error(`Cannot remove builtin sub-agent ${id}`);
      return false;
    }

    this.subagents.delete(id);
    logger.info(`Removed sub-agent: ${agent.name}`);
    return true;
  }

  /**
   * Update a sub-agent configuration
   */
  updateSubAgent(id: string, updates: Partial<SubAgentConfig>): boolean {
    const agent = this.getSubAgent(id);
    if (!agent) {
      logger.error(`Cannot update sub-agent ${id}: not found`);
      return false;
    }

    if (agent.isBuiltin) {
      logger.error(`Cannot update builtin sub-agent ${id}`);
      return false;
    }

    const updated = { ...agent, ...updates, id }; // Preserve ID
    this.subagents.set(id, updated);
    logger.info(`Updated sub-agent: ${agent.name}`);
    return true;
  }

  /**
   * Get SDK-compatible agents configuration
   * 
   * This returns the format expected by Claude Agent SDK's `agents` parameter:
   * {
   *   'agent-id': {
   *     description: '...',
   *     prompt: '...',
   *     tools: ['Read', 'Write'],
   *     model: 'sonnet'
   *   }
   * }
   * 
   * If a sub-agent has associated skillIds, it will inherit:
   * - Tools from those skills
   * - System prompts from those skills (merged with sub-agent's prompt)
   */
  getAgentsConfig(): Record<string, SdkAgentConfig> {
    const config: Record<string, SdkAgentConfig> = {};

    for (const agent of this.subagents.values()) {
      // Start with base configuration
      let tools = agent.tools ? [...agent.tools] : undefined;
      let prompt = agent.prompt;

      // If associated with skills, inherit their tools and prompts
      if (agent.skillIds && agent.skillIds.length > 0 && this.skillsManager) {
        const skillTools: string[] = [];
        const skillPrompts: string[] = [];

        for (const skillId of agent.skillIds) {
          const skill = this.skillsManager.getSkill(skillId);
          if (skill) {
            // Collect tool names from skill
            skill.tools.forEach(tool => {
              const toolName = tool.name;
              if (!skillTools.includes(toolName)) {
                skillTools.push(toolName);
              }
            });

            // Collect system prompts from skill
            if (skill.systemPrompt) {
              skillPrompts.push(skill.systemPrompt);
            }
          }
        }

        // Merge tools (skill tools + agent-specific tools)
        if (skillTools.length > 0) {
          tools = tools ? [...new Set([...tools, ...skillTools])] : skillTools;
        }

        // Merge prompts (skill prompts + agent prompt)
        if (skillPrompts.length > 0) {
          prompt = [...skillPrompts, agent.prompt].join('\n\n');
        }
      }

      const sdkConfig: SdkAgentConfig = {
        description: agent.description,
        prompt,
      };

      if (tools) {
        sdkConfig.tools = tools;
      }

      if (agent.model) {
        sdkConfig.model = agent.model;
      }

      config[agent.id] = sdkConfig;
    }

    return config;
  }

  /**
   * Get statistics about registered sub-agents
   */
  getStats(): {
    total: number;
    builtin: number;
    custom: number;
    byCategory: Record<SubAgentCategory, number>;
  } {
    const agents = this.getAllSubAgents();
    const stats = {
      total: agents.length,
      builtin: agents.filter(a => a.isBuiltin).length,
      custom: agents.filter(a => !a.isBuiltin).length,
      byCategory: {} as Record<SubAgentCategory, number>,
    };

    // Count by category
    agents.forEach(agent => {
      if (agent.category) {
        stats.byCategory[agent.category] = (stats.byCategory[agent.category] || 0) + 1;
      }
    });

    return stats;
  }

  /**
   * Export sub-agents configuration (for backup/sharing)
   */
  exportConfig(): SubAgentConfig[] {
    return this.getAllSubAgents();
  }

  /**
   * Import sub-agents configuration (from backup/sharing)
   */
  importConfig(configs: SubAgentConfig[], overwrite = false): {
    imported: number;
    skipped: number;
    errors: string[];
  } {
    const result = {
      imported: 0,
      skipped: 0,
      errors: [] as string[],
    };

    for (const config of configs) {
      try {
        // Validate required fields
        if (!config.id || !config.name || !config.description || !config.prompt) {
          result.errors.push(`Invalid config for ${config.id || 'unknown'}: missing required fields`);
          continue;
        }

        // Check if already exists
        if (this.subagents.has(config.id) && !overwrite) {
          result.skipped++;
          continue;
        }

        this.registerSubAgent(config);
        result.imported++;
      } catch (error) {
        result.errors.push(`Failed to import ${config.id}: ${error}`);
      }
    }

    return result;
  }
}

// Export singleton instance (will be initialized with SkillsManager in index.ts)
let _subAgentManager: SubAgentManager | null = null;

export function initializeSubAgentManager(skillsManager?: SkillsManager): SubAgentManager {
  if (!_subAgentManager) {
    _subAgentManager = new SubAgentManager(skillsManager);
  }
  return _subAgentManager;
}

export function getSubAgentManager(): SubAgentManager {
  if (!_subAgentManager) {
    throw new Error('SubAgentManager not initialized. Call initializeSubAgentManager() first.');
  }
  return _subAgentManager;
}

// For backward compatibility
export const subAgentManager = new SubAgentManager();

